package com.coupon.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coupon.admin.dto.CouponUseDTO;
import com.coupon.admin.dto.CouponVerifyDTO;
import com.coupon.admin.entity.Coupon;
import com.coupon.admin.entity.UserCoupon;
import com.coupon.admin.mapper.UserCouponMapper;
import com.coupon.admin.service.CouponUseService;
import com.coupon.admin.service.CouponService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 优惠券使用与核销服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CouponUseServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon> 
        implements CouponUseService {
    
    private final CouponService couponService;
    private final ObjectMapper objectMapper;
    private final RedisTemplate<String, Object> redisTemplate;
    
    private static final String COUPON_USE_LOCK_KEY = "coupon:use:lock:";
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserCoupon useCouponForOrder(CouponUseDTO useDTO) {
        Long userId = useDTO.getUserId();
        Long userCouponId = useDTO.getUserCouponId();
        Long orderId = useDTO.getOrderId();
        
        // 获取分布式锁
        String lockKey = COUPON_USE_LOCK_KEY + userCouponId;
        Boolean lockAcquired = redisTemplate.opsForValue()
                .setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
        
        if (!lockAcquired) {
            throw new RuntimeException("券正在使用中，请稍后再试");
        }
        
        try {
            // 获取用户券
            UserCoupon userCoupon = getById(userCouponId);
            if (userCoupon == null) {
                throw new RuntimeException("券不存在");
            }
            
            // 校验券状态
            if (!"UNUSED".equals(userCoupon.getStatus())) {
                throw new RuntimeException("券已使用或已过期");
            }
            
            // 校验券是否可用
            if (!isCouponAvailable(userCouponId, useDTO.getOrderAmount(), useDTO.getProductIds())) {
                throw new RuntimeException("券不满足使用条件");
            }
            
            // 计算抵扣金额
            BigDecimal discountAmount = calculateDiscountAmount(
                userCoupon.getCouponId(), useDTO.getOrderAmount(), useDTO.getProductIds());
            
            // 更新券状态
            userCoupon.setStatus("USING");
            userCoupon.setOrderId(orderId);
            userCoupon.setActualDiscount(discountAmount);
            
            updateById(userCoupon);
            
            log.info("用户{}使用券{}，订单ID：{}，抵扣金额：{}", 
                userId, userCouponId, orderId, discountAmount);
            
            return userCoupon;
            
        } finally {
            // 释放锁
            redisTemplate.delete(lockKey);
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean verifyCouponOffline(CouponVerifyDTO verifyDTO) {
        String couponCode = verifyDTO.getCouponCode();
        Long merchantId = verifyDTO.getMerchantId();
        
        // 根据券码查找用户券
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getCouponCode, couponCode);
        
        UserCoupon userCoupon = getOne(wrapper);
        if (userCoupon == null) {
            throw new RuntimeException("券码不存在");
        }
        
        // 校验券状态
        if (!"USING".equals(userCoupon.getStatus())) {
            throw new RuntimeException("券状态异常，无法核销");
        }
        
        // 校验券是否过期
        if (userCoupon.getExpireTime().isBefore(LocalDateTime.now())) {
            throw new RuntimeException("券已过期");
        }
        
        // 执行核销
        userCoupon.setStatus("USED");
        userCoupon.setMerchantId(merchantId);
        userCoupon.setVerifyTime(LocalDateTime.now());
        userCoupon.setVerifyType(verifyDTO.getVerifyType());
        
        if (verifyDTO.getVerifyAmount() != null) {
            userCoupon.setActualDiscount(verifyDTO.getVerifyAmount());
        }
        
        boolean result = updateById(userCoupon);
        
        if (result) {
            // 更新券的使用统计
            couponService.updateById(new Coupon() {{
                setId(userCoupon.getCouponId());
                setUsedCount(1);
            }});
            
            log.info("线下核销券成功，券码：{}，商户：{}", couponCode, merchantId);
        }
        
        return result;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean autoVerifyCoupon(Long orderId) {
        // 查找该订单使用的券
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getOrderId, orderId)
               .eq(UserCoupon::getStatus, "USING");
        
        List<UserCoupon> userCoupons = list(wrapper);
        
        boolean allSuccess = true;
        for (UserCoupon userCoupon : userCoupons) {
            try {
                userCoupon.setStatus("USED");
                userCoupon.setUseTime(LocalDateTime.now());
                userCoupon.setVerifyTime(LocalDateTime.now());
                userCoupon.setVerifyType("AUTO");
                
                boolean result = updateById(userCoupon);
                if (!result) {
                    allSuccess = false;
                } else {
                    // 更新券的使用统计
                    updateCouponUsedCount(userCoupon.getCouponId());
                }
                
                log.info("自动核销券成功，券ID：{}，订单ID：{}", userCoupon.getId(), orderId);
                
            } catch (Exception e) {
                log.error("自动核销券失败，券ID：{}，订单ID：{}", userCoupon.getId(), orderId, e);
                allSuccess = false;
            }
        }
        
        return allSuccess;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean releaseCoupon(Long orderId) {
        // 查找该订单使用的券
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getOrderId, orderId)
               .eq(UserCoupon::getStatus, "USING");
        
        List<UserCoupon> userCoupons = list(wrapper);
        
        boolean allSuccess = true;
        for (UserCoupon userCoupon : userCoupons) {
            try {
                userCoupon.setStatus("UNUSED");
                userCoupon.setOrderId(null);
                userCoupon.setActualDiscount(BigDecimal.ZERO);
                
                boolean result = updateById(userCoupon);
                if (!result) {
                    allSuccess = false;
                }
                
                log.info("释放券成功，券ID：{}，订单ID：{}", userCoupon.getId(), orderId);
                
            } catch (Exception e) {
                log.error("释放券失败，券ID：{}，订单ID：{}", userCoupon.getId(), orderId, e);
                allSuccess = false;
            }
        }
        
        return allSuccess;
    }
    
    @Override
    public List<UserCoupon> getAvailableCoupons(Long userId, BigDecimal orderAmount, List<Long> productIds) {
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getUserId, userId)
               .eq(UserCoupon::getStatus, "UNUSED")
               .gt(UserCoupon::getExpireTime, LocalDateTime.now());
        
        List<UserCoupon> userCoupons = list(wrapper);
        
        // 过滤出可用的券
        return userCoupons.stream()
                .filter(userCoupon -> isCouponAvailable(userCoupon.getId(), orderAmount, productIds))
                .toList();
    }
    
    @Override
    public BigDecimal calculateDiscountAmount(Long couponId, BigDecimal orderAmount, List<Long> productIds) {
        Coupon coupon = couponService.getById(couponId);
        if (coupon == null) {
            return BigDecimal.ZERO;
        }
        
        // 检查使用门槛
        if (orderAmount.compareTo(coupon.getThreshold()) < 0) {
            return BigDecimal.ZERO;
        }
        
        // 检查适用范围
        if (!isCouponApplicable(coupon, productIds)) {
            return BigDecimal.ZERO;
        }
        
        // 计算抵扣金额
        BigDecimal discountAmount = BigDecimal.ZERO;
        
        switch (coupon.getType()) {
            case "DIRECT_REDUCTION":
                // 立减券
                discountAmount = coupon.getValue();
                break;
                
            case "FULL_REDUCTION":
                // 满减券
                discountAmount = coupon.getValue();
                break;
                
            case "DISCOUNT":
                // 折扣券
                discountAmount = orderAmount.multiply(BigDecimal.ONE.subtract(coupon.getValue()));
                break;
                
            case "LADDER":
                // 阶梯券
                discountAmount = calculateLadderDiscount(coupon, orderAmount);
                break;
                
            default:
                discountAmount = BigDecimal.ZERO;
        }
        
        // 确保抵扣金额不超过订单金额
        return discountAmount.min(orderAmount);
    }
    
    @Override
    public boolean triggerSceneCoupon(Long userId, String sceneType, Object sceneData) {
        // TODO: 实现场景触发券推送逻辑
        // 1. 根据场景类型匹配相应的券
        // 2. 检查用户是否符合条件
        // 3. 推送券到用户券包
        // 4. 发送通知
        
        log.info("场景触发券推送，用户：{}，场景：{}", userId, sceneType);
        return true;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchVerifyCoupons(List<Long> userCouponIds, Long merchantId, String verifyType) {
        LambdaUpdateWrapper<UserCoupon> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(UserCoupon::getId, userCouponIds)
                    .eq(UserCoupon::getStatus, "USING")
                    .set(UserCoupon::getStatus, "USED")
                    .set(UserCoupon::getMerchantId, merchantId)
                    .set(UserCoupon::getVerifyTime, LocalDateTime.now())
                    .set(UserCoupon::getVerifyType, verifyType);
        
        boolean result = update(updateWrapper);
        
        if (result) {
            log.info("批量核销券成功，数量：{}，商户：{}", userCouponIds.size(), merchantId);
        }
        
        return result;
    }
    
    @Override
    public List<UserCoupon> getCouponVerifyHistory(Long couponId, String verifyType) {
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getCouponId, couponId)
               .eq(UserCoupon::getStatus, "USED");
        
        if (verifyType != null) {
            wrapper.eq(UserCoupon::getVerifyType, verifyType);
        }
        
        wrapper.orderByDesc(UserCoupon::getVerifyTime);
        
        return list(wrapper);
    }
    
    @Override
    public boolean isCouponAvailable(Long userCouponId, BigDecimal orderAmount, List<Long> productIds) {
        UserCoupon userCoupon = getById(userCouponId);
        if (userCoupon == null) {
            return false;
        }
        
        // 检查券状态
        if (!"UNUSED".equals(userCoupon.getStatus())) {
            return false;
        }
        
        // 检查是否过期
        if (userCoupon.getExpireTime().isBefore(LocalDateTime.now())) {
            return false;
        }
        
        // 检查使用门槛和适用范围
        Coupon coupon = couponService.getById(userCoupon.getCouponId());
        if (coupon == null) {
            return false;
        }
        
        // 检查使用门槛
        if (orderAmount.compareTo(coupon.getThreshold()) < 0) {
            return false;
        }
        
        // 检查适用范围
        return isCouponApplicable(coupon, productIds);
    }
    
    /**
     * 检查券是否适用于指定商品
     */
    private boolean isCouponApplicable(Coupon coupon, List<Long> productIds) {
        if ("ALL".equals(coupon.getScope())) {
            return true;
        }
        
        if (productIds == null || productIds.isEmpty()) {
            return false;
        }
        
        try {
            if ("PRODUCT".equals(coupon.getScope()) && coupon.getScopeIds() != null) {
                List<Long> applicableProductIds = objectMapper.readValue(
                    coupon.getScopeIds(), 
                    objectMapper.getTypeFactory().constructCollectionType(List.class, Long.class)
                );
                
                return productIds.stream().anyMatch(applicableProductIds::contains);
            }
            
            // TODO: 实现品类范围检查
            
        } catch (JsonProcessingException e) {
            log.error("解析券适用范围失败", e);
            return false;
        }
        
        return false;
    }
    
    /**
     * 计算阶梯券抵扣金额
     */
    private BigDecimal calculateLadderDiscount(Coupon coupon, BigDecimal orderAmount) {
        // TODO: 实现阶梯券抵扣计算逻辑
        // 根据ladderConfig配置计算阶梯折扣
        
        return coupon.getValue();
    }
    
    /**
     * 更新券的使用统计
     */
    private void updateCouponUsedCount(Long couponId) {
        LambdaUpdateWrapper<Coupon> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Coupon::getId, couponId)
                    .setSql("used_count = used_count + 1");
        
        couponService.update(updateWrapper);
    }
}
